﻿using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using Zove.Compiler;
using System.IO;
using System.Configuration;
using Zove.Runtime;
using FunctionalCLR.Core;

namespace Zove.Test
{
    [TestFixture]
    public class TestAutomatedModeling
    {
        List<string> angles = new List<string>();

        List<string> edges = new List<string>();

        List<string> triangles = new List<string>();

        public static string Object(params char[] c)
        {
            return new string(c);
        }

        public static string[] IsVariableBuilt(List<string> n, params char[] m)
        {
            List<string> found = new List<string>();

            bool success = false;
            foreach (string t in n)
            {
                success = true;
                foreach (char c in m)
                {
                    if (!t.Contains(c.ToString()))
                    {
                        success = false;
                        break;
                    }
                }
                if (success)
                {
                    found.Add(t);
                }
            }

            return found.ToArray();
        }

        public ZoomClass Build(string className, char[] v)
        {
            ZoomClass c = new ZoomClass();
            c.Name = className;

            foreach (char i in v)
            {
                foreach (char j in v)
                {
                    if (i == j)
                    {
                        continue;
                    }

                    ZoomVariable edge = new ZoomVariable();
                    edge.Type = "factor";
                    edge.Name = Object(i, j);
                    c.Variables.Add(edge);

                    string[] similarEdges = IsVariableBuilt(edges, i, j);
                    if (similarEdges.Length > 0)
                    {
                        ZoomEquation equ = new ZoomEquation();
                        equ.Equation = edge.Name + " = " + similarEdges[0];

                        c.Equations.Add(equ);
                    }
                    foreach (char k in v)
                    {
                        if (k == i || k == j)
                        {
                            continue;
                        }

                        string angle = "a_" + Object(i, j, k);
                        ZoomVariable va = new ZoomVariable();
                        va.Name = angle;
                        va.Type = "factor";
                        c.Variables.Add(va);
                        angles.Add(angle);

                        if (IsVariableBuilt(triangles, i, j, k).Length == 0)
                        {
                            // any three vertices form a triangle
                            ZoomVariable triangle = new ZoomVariable();
                            triangle.Type = "triangle";
                            triangle.Name = "t_" + Object(i, j, k);
                            c.Variables.Add(triangle);
                            triangles.Add(Object(i, j, k));

                            ZoomEquation equ = new ZoomEquation();
                            equ.Equation = triangle.Name + ".a = " + Object(i, j);
                            c.Equations.Add(equ);

                            equ = new ZoomEquation();
                            equ.Equation = triangle.Name + ".b = " + Object(i, k);
                            c.Equations.Add(equ);

                            equ = new ZoomEquation();
                            equ.Equation = triangle.Name + ".c = " + Object(j, k);
                            c.Equations.Add(equ);

                            equ = new ZoomEquation();
                            equ.Equation = triangle.Name + ".A = " + "a_" + Object(i, k, j);
                            c.Equations.Add(equ);

                            equ = new ZoomEquation();
                            equ.Equation = triangle.Name + ".B = " + "a_" + Object(k, i, j);
                            c.Equations.Add(equ);

                            equ = new ZoomEquation();
                            equ.Equation = triangle.Name + ".C = " + "a_" + Object(i, j, k);
                            c.Equations.Add(equ);
                        }
                    }
                }
            }

            foreach (char i in v)
            {
                foreach (char j in v)
                {
                    if (j == i)
                    {
                        continue;
                    }

                    foreach (char k in v)
                    {
                        if (k == i || k == j)
                        {
                            continue;
                        }


                        ZoomEquation e = new ZoomEquation();
                        e.Equation = "a_" + Object(j, i, k) + " = " + "a_" + Object(k, i, j);

                        c.Equations.Add(e);
                    }
                }
            }

            return c;
        }

        [Test]
        public void TestIsVariableBuilt()
        {
            List<string> t = new List<string>();
            t.Add("abc");

            string[] f = IsVariableBuilt(t, 'a', 'b', 'c');
            Assert.AreEqual(1, f.Length);
        }

        [Test]
        public void TestBuild()
        {
            char[] v = new char[] { 'a', 'b', 'c', 'd' };

            ZoomClass c = Build("Polygon", v);
            Console.WriteLine(c.ToString());

            string path = Utils.ModelPath.Split(';')[0];
            File.WriteAllText(path + "\\Polygon.zoom", c.ToString(), Encoding.UTF8);
            
            Dictionary<string, double> i = new Dictionary<string, double>();
            i["ab"] = 6;
            i["ac"] = 5;
            i["a_bac"] = Math.PI / 2;
            i["a_abc"] = Math.PI / 2;
            i["a_acb"] = Math.PI / 2;

            RuntimeTests.TestModel("polygon", i);
        }
    }
}
